/** JTalkerClientProtocol transmission protocol 
 *  @author ChrM */

package com.jtalker.client;

import javax.swing.JOptionPane;

import com.jtalker.client.JTalkerParser.OneMember;
import com.jtalker.client.JTalkerParser.OneMessage;

/**
 * A kind of protocol that manipulate the message between server and client. For instance XML message protocol.
 * 
 * @author Administrator
 * 
 */
public class JTalkerClientProtocol {
	/** Constructor */
	public JTalkerClientProtocol(JTalkerClient parent) {
		this.parentClient = parent;
	}

	/** Produce message.Sends user status (must be set in the main class!) */
	public boolean sendUserStatus(boolean sendPasswd) {
		String stream = "<JTALKER><MEMBER name=\"";
		stream += (this.parentClient.userName + "\" status=\"" + this.parentClient.userStatus + "\" ");
		if (sendPasswd) {
			// Create MD5-hash of password
			try {
				stream += ("passwd=\"" + MD5Password.hashPassword(this.parentClient.userPasswd + "\n") + "\" />");
			} catch (Exception e) {
				stream += ("passwd=\"\" />");
			}
		} else {
			stream += "/>";
		}
		stream += "</JTALKER>";

		return this.sendPackage(stream);
	}

	/** Send data for a new account */
	public boolean sendNewAccount(String userName, String password) {
		String stream = "<JTALKER><NEW_MEMBER name=\"";
		stream += (userName + "\" ");
		// Create MD5-hash of password
		try {
			stream += ("passwd=\"" + MD5Password.hashPassword(password + "\n") + "\" />");
		} catch (Exception e) {
			return false;
		}
		stream += "</JTALKER>";

		return this.sendPackage(stream);
	}

	/** Formats and sends a message (formated with HTML) */
	public boolean sendMessage(String message, String receiver, String type, String subject, String id) {
		// prepare String
		try {
			message = toHTMLString(message);
			if (type == null) {
				type = "normal";
			}
			/*
			 * if(_type == "command") this.parent.setLastCommandResponse(null, null, null);
			 */
			if (receiver != null && (receiver.indexOf(" AT ") != -1)) {
				receiver = receiver.substring(0, receiver.lastIndexOf(" AT "));
			}
			String stream = "<JTALKER><MESSAGE content=\"";
			stream += (message + "\" ");
			if (receiver != null) {
				stream += ("to=\"" + receiver + "\" type=\"" + type + "\"");
			} else {
				stream += ("type=\"" + type + "\"");
			}
			if (id != null) {
				stream += (" id=\"" + id + "\"");
			}
			if (subject != null) {
				stream += (" subject=\"" + subject + "\"");
			}
			stream += " /></JTALKER>";
			return this.sendPackage(stream);
		} catch (Exception e) {
			System.err.println("*** Can't send! " + e.toString());
			return false;
		}
	}

	/** Save received data */
	private boolean sendPackage(String send) {
		return this.parentClient.sendToServer(send);
	}

	/** Process servers package */
	public boolean processServerPackage(String serverPackage) {
		JTalkerParser tempParser = new JTalkerParser();
		if (!tempParser.parsing(serverPackage)) {
			return false;
		}
		/*
		 * if(tmpParser == null) { System.err.println("*** Parser gets null!"); return false; }
		 */
		boolean updateUserList = false;
		// save member List
		try {
			// String server_message = tmpParser.getError();
			String serverMessage = tempParser.getAnswer();
			if (serverMessage != null) {
				if (tempParser.getAnswerType() == JTalkerParser.ANSWER_ERROR) {
					System.err.println("*** (GET) Error: " + serverMessage);
					// / Only for the GUI-Version !!! Delete this for the
					// console client!
					// TODO: make this message box not modal!!!
					JOptionPane.showMessageDialog(null, "Server message:\n" + serverMessage, "Server answer (ERROR)",
							JOptionPane.ERROR_MESSAGE);

					if (this.parentClient.STATE == JTalkerClient.STATE_LOGGING
							|| this.parentClient.STATE == JTalkerClient.STATE_ACCOUNT_CREATION) {
						this.parentClient.closeConnection();
						return true;
					}
				} else if (tempParser.getAnswerType() == JTalkerParser.ANSWER_INFO) {
					System.err.println("*** (GET) Info: " + serverMessage);
					// Only for the GUI-Version !!! Delete this for the console client!
					// TODO: make this message box not modal!!!
					JOptionPane.showMessageDialog(null, "Server message:\n" + serverMessage, "Server answer (INFO)",
							JOptionPane.INFORMATION_MESSAGE);
				} else if (tempParser.getAnswerType() == JTalkerParser.ANSWER_UPDATE) {
					System.err.println("*** (GET) Update notification");
					this.sendUserStatus(false);
				} else {
					System.err.println("*** (GET) Undef: " + serverMessage);
					// / Only for the GUI-Version !!! Delete this for the
					// console client!
					// TODO: make this message box not modal!!!
					JOptionPane.showMessageDialog(null, "Server message:\n" + serverMessage,
							"Server answer (UNDEFINED)", JOptionPane.INFORMATION_MESSAGE);
				}
				// Close connection if we've got an answer for account creation
				if (this.parentClient.STATE == JTalkerClient.STATE_ACCOUNT_CREATION) {
					this.parentClient.closeConnection();
					return true;
				}
			}

			if (this.parentClient.STATE == JTalkerClient.STATE_LOGGING) {
				this.parentClient.STATE = JTalkerClient.STATE_CONNECTED;
			}

			// Save Command Response
			/*
			 * String tmpCommandResponse = tmpParser.getCommandResponse(); if(tmpCommandResponse != null) {
			 * this.parent.setLastCommandResponse(tmpCommandResponse); }
			 */

			for (int i = 0; i < tempParser.getMemberNum(); i++) {
				OneMember member = tempParser.getAMember(i);
				this.parentClient.addMember(member.name, member.status, member.type, null, member.ip, null, null);

				if (!updateUserList) {
					updateUserList = true;
				}
			}
			// save messages
			for (int i = 0; i < tempParser.getMessagesNum(); i++) {
				OneMessage message = tempParser.getAMessage(i);
				if (!message.messageType.equals("command_response")) {
					if (message.messageType.equals("command")) {
						// TODO: send return value to caller
						String retVal = this.parentClient.getFrontend().getPluginLoader()
								.invokePlugInMethod(message.content, message.sender);

						if (null == retVal) {
							String errMsg = this.parentClient.getFrontend().getPluginLoader().getLastError();
							System.out.println("*** Can't invoke:" + errMsg);
							this.parentClient.sendMessage(errMsg, message.sender, "error", null, message.id);
						} else {
							this.parentClient.sendMessage(retVal, message.sender, "command_response",
									message.messageSubject, message.id);
						}
					} else {
						this.parentClient.addMember(message.sender, message.senderStatus, null, message.content, null,
								message.messageSubject, message.messageType);
					}
				} else {
					this.parentClient.setLastCommandResponse(message.id, message.sender, message.content);
				}
			}
			if (updateUserList) {
				this.parentClient.cleanUpList(tempParser);
			}
		} catch (Exception e) {
			System.err.println("*** Protocol: Exception while parsing received data: " + e.toString());
			e.printStackTrace();
			return false;
		}

		return true;
	}

	/**
	 * Returns the specified string converted to a format suitable for HTML. All single-quote, double-quote,
	 * greater-than, less-than and ampersand characters are replaces with their corresponding HTML Character Entity
	 * code.
	 * 
	 * @param in
	 *            the String to convert
	 * @return the converted String
	 */
	public static String toHTMLString(String in) {
		StringBuffer out = new StringBuffer();
		for (int i = 0; in != null && i < in.length(); i++) {
			char c = in.charAt(i);
			if (c == '\'') {
				out.append("&#39;");
			} else if (c == '\"') {
				out.append("&#34;");
			} else if (c == '<') {
				out.append("&lt;");
			} else if (c == '>') {
				out.append("&gt;");
			} else if (c == '&') {
				out.append("&amp;");
			} else if (c == '\n') {
				out.append("_");
			} else if (c == '\r') {
				out.append("_");
			} else {
				out.append(c);
			}
		}
		return out.toString();
	}

	private JTalkerClient parentClient;
}
